package com.autumn.cloud.demo.consumer.controllers;

import com.autumn.cloud.demo.common.constants.DemoServiceProviderUrlConstants;
import com.autumn.cloud.demo.common.model.UserInfo;
import com.autumn.cloud.demo.common.service.ProviderCommonService;
import com.autumn.cloud.demo.consumer.configure.ClientAutoConfigure;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;
import java.util.Random;

/**
 * <p>
 * </p>
 *
 * @description TODO
 * @author: 老码农
 * @create: 2020-12-10 18:50
 **/
@RestController
@Slf4j
public class UserController {

    private final ProviderCommonService providerCommonService;
    private final DiscoveryClient discoveryClient;
    @Resource(name = ClientAutoConfigure.BEAN_REST_BALANCED_TEMPLATE, description = "负载均衡")
    private RestTemplate restBalancedTemplate;

    @Resource(name = ClientAutoConfigure.BEAN_REST_TEMPLATE, description = "普通调用")
    private RestTemplate restTemplate;

    public UserController(ProviderCommonService providerCommonService,
                          DiscoveryClient discoveryClient) {
        this.providerCommonService = providerCommonService;
        this.discoveryClient = discoveryClient;
    }

    /**
     * demo 服务器列表
     *
     * @return
     */
    @GetMapping(path = "server/demo/list")
    public List<ServiceInstance> demoServerList() {
        List<ServiceInstance> instances = discoveryClient.getInstances(this.providerCommonService.getDemoServiceName());
        return instances;
    }

    /**
     * 用户信息
     *
     * @return
     */
    @HystrixCommand(fallbackMethod = "userInfoHystrix")
    @GetMapping(path = DemoServiceProviderUrlConstants.USER_INFO_URL)
    public UserInfo userInfo() {
        String url = this.providerCommonService.getDemoServiceUrl() + DemoServiceProviderUrlConstants.USER_INFO_URL;
        log.info("用户信息请求--ribbon-client(Url):" + url);
        UserInfo userInfo = this.restBalancedTemplate.getForObject(url, UserInfo.class);
        if (userInfo == null) {
            return null;
        }
        userInfo.setMsg(userInfo.getMsg() + " -> ribbon-client 转发(负载均衡)");
        log.info("用户信息请求--ribbon-client(负载均衡)");
        return userInfo;
    }

    private final Random random = new Random();

    /**
     * 手动负载均衡
     *
     * @return
     */
    private ServiceInstance demoService() {
        List<ServiceInstance> instances = this.discoveryClient.getInstances(this.providerCommonService.getDemoServiceName());
        if (instances.size() == 0) {
            throw new RuntimeException("没有可用的服务");
        }
        if (instances.size() == 1) {
            return instances.get(0);
        }
        // 随机，如果需要实现分配均，则需要重算法
        int i = this.random.nextInt(instances.size());
        return instances.get(i);
    }

    /**
     * 用户信息
     *
     * @return
     */
    @HystrixCommand(fallbackMethod = "userInfoHystrix")
    @GetMapping(path = DemoServiceProviderUrlConstants.USER_INFO_URL + "/1")
    public UserInfo userInfo1() {
        // 获取服务实例
        ServiceInstance serviceInstance = this.demoService();
        String url = serviceInstance.getUri() + DemoServiceProviderUrlConstants.USER_INFO_URL;
        log.info("用户信息请求--ribbon-client(Url):" + url);
        UserInfo userInfo = this.restTemplate.getForObject(url, UserInfo.class);
        if (userInfo == null) {
            return null;
        }
        userInfo.setMsg(userInfo.getMsg() + " -> ribbon-client 转发(普通调用)");
        log.info("用户信息请求--ribbon-client(普通调用)");
        return userInfo;
    }

    private UserInfo userInfoHystrix() {
        UserInfo userInfo = new UserInfo();
        userInfo.setMsg("Ribbon 熔断，服务器已断开，暂时无法访问");
        return userInfo;
    }
}